﻿#ifndef GAME_H
#define GAME_H

#include "WordLib.h"
#include "Player.h"


#include "Global/GameGlobal.h"
#include "Global/GlobalClass.h"
#include "Global/SocketGlobal.h"
#include "Socket/ClientSocket.h"


#include <QObject>
#include <QWaitCondition>
#include <QMutex>
#include <QThread>
#include <QList>




//点击牌返回的参数
//如果点击类型是Wujiang,则nPlayerID是武将ID,否则是所在类型下标
struct DianJiPai
{
public:
    //0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096
    int         iID;
    BASE_PAI::_Areas  nType;			//牌 类型(手牌/人/武器/防具/马/判定区)
    int         iFlag;			//牌 状态

    int         nPlayerID;		//牌 所属玩家ID
    int         nValue;			//牌 值
    BASE_PAI    *pObject;
public:
    DianJiPai();
};


//选牌的 某个步骤
struct PokeStep
{
public:
    bool        bSelfFlag;		//牌 是否选自己的区域(off)
    bool        bMultipleFlag;	//牌 可以多选
    int         nTotalCount;	//牌 每步要选的总数
    BASE_PAI::_Areas nType;			//牌 GameSlot类型(手牌/人/武器/防具/马/判定区),可按位叠加

    int         nSelectPlayerID;					//牌 所属对象,无(按钮和敌人)则-1
    int         nSelectCount;						//牌 已选个数
    int         nSelectValue[GAME_MAX_NUM_CHOICE];	//牌 选择的值
    BASE_PAI::_Areas  nSelectType[GAME_MAX_NUM_CHOICE];	//牌 类型(手牌/人/武器/防具/马/判定区)
//	char        strMsg[GAME_MAX_NUM_MSG];			//选牌时显示的信息
public:
    PokeStep();
};





class _GAME : public QThread
{
    Q_OBJECT
    Q_ENUMS(_GameButtonValue)
    Q_ENUMS(_GameShenFen)
    Q_PROPERTY(QObjectList pokeList READ pokeList)
    Q_PROPERTY(QObjectList playerList READ playerList)
    Q_PROPERTY(QObjectList wuJiangList READ wuJiangList)
    Q_PROPERTY(QObject* word READ word)
public:
    enum _GameType      //游戏类型
    {
        Game_Type_NULL = 0,
        Game_Type_1
    };
    enum _GameStatus
    {
        Game_Status_Continue = 0,
        //Game_Status_NextTurn,
        Game_Status_GameOver,
        Game_Status_Exit,
        Game_Status_Err
    };
    enum _GameButtonValue
    {
        Game_Button_Err = -1,
        Game_Button_OK = 0,
        Game_Button_Cancel = 1,
        Game_Button_Giveup = 2
    };
    enum _GameShenFen
    {
        Game_ShenFen_NULL,
        Game_ShenFen_1,
        Game_ShenFen_2,
        Game_ShenFen_3,
        Game_ShenFen_4
    };

    //出牌函数的类型参数
    enum _GameChuPaiType
    {
        Game_ChuPai_Type_ZhuDong = 0,
        Game_ChuPai_Type_BeiDong,
        Game_ChuPai_Type_QiPai
    };


//游戏初始化数据:
    _GameType   eGameType;
    int			playerCount;    //玩家数
    int			iMyID;          //本人ID(下标)
    bool        isMaster;       //是否房主

    QList<_Player::JiaoSe> jiaoSeList;
	
//游戏数据
    _Player*    m_Player;//[GAME_MAX_NUM_PLAYER];		//玩家
    _Pai*       m_PaiDui;		//牌堆
    _WuJiang*   m_WuJiang;		//武将
    //3个按钮的值,确定0,取消1,弃牌2,也是下标
    BASE_PAI::_Flags        Button[3];

    WordLib*    wordLib;        //单词库

    QHash<int,QStringList>       msgHash;        //所有提示字符串 hash


//游戏使用中数据
    //pai yuanshipaidui[2][4][13];	//4种花色,13个点数
    _Pai*       PaiDui[GAME_MAX_NUM_PAI];		//牌堆
    _Pai*       QiPaiDui[GAME_MAX_NUM_PAI];	//弃牌堆

    int			PaiDuiShu;
    int			QiPaiDuiShu;
    long        PaiDuiID[GAME_MAX_NUM_PAI];     //牌堆ID存放顺序(用来发送),实际存的比ID大1!

    int			iMainTurn;		//谁的回合
    _GameShenFen eWinner;		//0:平;1:主公2:忠臣;3:反贼;4:内奸
    _GameStatus eGameStatus;      //游戏状态,结束,继续,强制退出,错误等


    bool        answer;     //问题答案是否正确

	//In:
    DianJiPai	dianjipai;                      //点击牌的返回值
	//Out:
    PokeStep	step[GAME_MAX_NUM_STEP];		//出牌步骤
    QString		shortMsg;		//出牌消息
    QString     str;

public:
    _WordObject wordObj;            //单词对象(qml暴露用)

private:

    //QML暴露用,所有出现的对象列表
    QObjectList m_PlayerList;      //[GAME_MAX_NUM_PLAYER];		//玩家
    QObjectList m_PaiDuiList;		//牌堆
    QObjectList m_WuJiangList;		//武将
    //QStringList m_StrList;



signals:
    //void s_FlagMenus2(QVariant ok, QVariant cancel, QVariant giveup);      //设置按钮状态
    //void s_FlagMenus1(BASE_PAI::_Flags ok, BASE_PAI::_Flags cancel, BASE_PAI::_Flags giveup);      //设置按钮状态
    void s_FlagMenus(int ok, int cancel, int giveup);      //设置按钮状态
    void s_DiaoXie(int w, int Blood);       //掉血
    void s_SetPlayerDead(int w);                //设置为死亡
    void s_GameInit(int playerCount,int myID);              //游戏初始化


    //void s_RefreshUI();         //刷新UI
    void s_ShowDebug(QString);                      //显示调试信息
    void s_ShowMessage(QString);                    //显示信息
    //void s_ShowShortMessage(QString);               //显示短消息
    void s_ShowChuPaiMessage(QString);               //显示短消息
    void s_ShowWenTiMessage(QString);               //显示短消息

    void s_RefreshAllPokePosition();                //刷新所有牌的位置
    void s_RefreshAllFlags();                       //刷新所有元素的flags

    void s_GameOver(int nRet);                      //游戏结束

    //answer为-2,用户选择;为-1,其他人/电脑选择;0以上:显示答案
    void s_Wenti(QObject *wenti, int answer);                       //显示问题
    void s_ShowPlayersArea(int player); //player为-1则隐藏


    void s_StartChuPai(int w);      //某个player准备选牌时发送
    void s_StopChuPai(int w);       //某个player一次选牌完毕时

    void s_ChuPaiOver(QVariantList list);       //出牌结束后的划线

    void s_SendToOthers();                      //发送数据






public:
    _GAME(QObject *parent = NULL);
    virtual ~_GAME();

    //属性
public:

    QObjectList pokeList() const
    {
        return m_PaiDuiList;
    }
    QObjectList playerList() const
    {
        return m_PlayerList;
    }
    QObjectList wuJiangList() const
    {
        return m_WuJiangList;
    }

    //Q_INVOKABLE QStringList strlist(){m_StrList.append("a");return m_StrList;}

    _WordObject* word()
    {
        return &wordObj;
    }
public:

    //初始化游戏
    //参数为 玩家个数
    virtual int Init();
    int ChoiceWuJiang(int count);

    //游戏开始
    _GameStatus GameBegin();
	
    //摸牌ok
    //牌堆;牌堆剩余牌数;弃牌堆;弃牌堆数
    //摸一张牌,然后返回此牌;出错返回NULL
    _Pai* Mo1Pai();
	//把p放入弃牌堆,返回弃牌堆数目
    int QiPai(_Pai *p);

    //返回 GAMEOVER 游戏结束;0 正常返回
    //w的回合
    //virtual int Huihe(int w);
	
    virtual _GameStatus HuiHeKaiShi(int w);
    virtual _GameStatus PanDingJieDuan(int w);
    virtual _GameStatus MoPaiJieDuan(int w);
    virtual _GameStatus ChuPaiJieDuan(int w);
    virtual _GameStatus QiPaiJieDuan(int w);
    virtual _GameStatus HuiHeJieShu(int w);



    _GameStatus PanDingChuLi(int w);
    _GameStatus MoPaiChuLi(int w);
    _GameStatus ChuPaiChuLi(int w);
    _GameStatus QiPaiChuLi(int w);




    //洗牌ok
    //将qipaidui随机放入paidui中,将所有qipaidui的leixing置为 -1,
    virtual void Xipai();
        void CreatePaiDuiID();  //相当于洗牌
        void RefreshPaiDui();


    //摸n张牌放入shoupai中,多余的放在弃牌堆
    void MoPai(int w,int n);

    //!!!!!!!!!!!!!!!!!!!!!
    //计算w1和w2距离,type=1计算距离(包括马),type=2计算杀距离(包括武器和马),还有注意死亡玩家
    bool ComputeDistent(int w1,int w2,int type)
    {
        int j1 = 1, j2 = 1;
        int i = GetNextPlayer(w1);
        for(; i != w2; i = GetNextPlayer(i))
        {
            j1++;
        }
        i = GetNextPlayer(w2);
        for(; i != w1; i = GetNextPlayer(i))
        {
            j2++;
        }

        //if(type == 1)
        {
            if(j1 > j2)j1 = j2;
            if(j1 <= 1)
                return true;
            return false;
        }

    }
	
	//得到w的下一个未死武将
	int GetNextPlayer(int w);

    QString getPlayerShowName(int w)
    {
        QString name = _T("<font size=5 color=#FF6060>%1</font>");
        if(w < 0 || w >= GAME_MAX_NUM_PLAYER)
            return name.arg("超出范围的武将!");
        if(m_Player[w].isMe())
            return name.arg("您");
        else if(m_Player[w].isComputer())
            return name.arg("小艾");
        else
            return name.arg("网络玩家");
    }

	//显示胜利者ok
	int ShowWinner();


    //晒点,返回0~5
    virtual int ShaiDian();
	
	


//死亡处理
	//w掉血x
    //如果体力>0或求桃成功,则Game_Status_Continue
	//如果死亡并游戏结束,返回GAMEOVER
    _GameStatus DiaoXie(int w,int x);
        //w1向w2求桃
        //有桃返回 Game_Button_OK,否则返回 Game_Button_Cancel
        _GameButtonValue Qiutao(int w1,int w2);

		//设置某人死亡并弃牌,返回游戏是否结束,
        _GameStatus SetPlayerDead(int w);
		
        //检测游戏是否结束,返回Game_Status_Continue或Game_Status_Gameover
    virtual _GameStatus CheckGameOver();
    _GameStatus setGameStatus(_GameStatus status)
    {
        if(eGameStatus == Game_Status_Continue && status != Game_Status_Continue)
            eGameStatus = status;
        return eGameStatus;
    }
	







//牌效果
    //w杀
    _GameStatus Sha(int w, int w1);

    //w出闪,出杀
    _GameButtonValue ChuShan(int w);
    _GameButtonValue ChuSha(int w);

	//w吃【桃】,返回体力值
    int ChiTao(int w);

    _GameStatus Chai(int w, int w1);
    _GameStatus Shun(int w, int w1);
    _GameStatus WuZhong(int w);
    _GameStatus JieDao(int w, int w1, int w2);
    _GameStatus WanJian(int w);
    _GameStatus NanMan(int w);
    _GameStatus GaoKao(int w, int w1);
    _GameStatus ShanDian(int w);
    _GameStatus Le(int w, int w1);

    _GameStatus ZhuangBeiWuQi(int w);


    //牌效果完毕后,进行弃牌处理
    //返回Game_Status_Continue or Game_Status_Gameover
    _GameStatus XiaoGuoQiPai();






public:
    //问英语,答案错误返回false
    virtual bool WenTi(int w)
    {
        return true;
    }
    virtual int ShowPlayersArea(int player) = 0;
    virtual int HidePlayersArea() = 0;

    //检测 玩家id 是否正确,且该玩家是否 活着且正在上场
    //bAll为true且 player<0时才为true(表示所有玩家)
    bool CheckPlayerPlay(int player,bool bAll)
    {
        if(player >= GAME_MAX_NUM_PLAYER)return false;
        else if(player >= 0)
        {
            if(m_Player[player].bDeadFlag == true || m_Player[player].bUsing == false)
                return false;
        }
        else
        {
            if(!bAll)
                return false;
        }
        return true;
    }







//设置状态函数集合:
    //设置按钮bEnable(0/1)
    void FlagMenus(BASE_PAI::_Flags ok, BASE_PAI::_Flags cancel, BASE_PAI::_Flags giveup);
    QList<_Player*> resetAllPlayers(QList<_Player*> list);

    //type:0,没死亡和上场的玩家
    QList<_Player*> getAllPlayers(int type = 0);

    QList<_Player*> removePlayer(QList<_Player*> list, int id);
    QList<_Player*> removePlayer(QList<_Player*> list, BASE_PAI::_Flags flags);
    QList<_Player*> retainPlayer(QList<_Player*> list, BASE_PAI::_Flags flags);
	
    //全部置为Flag_NULL;
    //将所有武将 等于/设置/取消 flag
    //type表示eFlags赋值方式(等于,设置,清除)
    //player = -1 表示所有,为0以上则除player外全部
    //返回可点个数
    QList<_Player*> flagAllPlayers(QList<_Player*> list, BASE_PAI::_Flags eFlags, BASE_PAI::_FlagType type = BASE_PAI::FlagType_Set);

    /*
    下面的函数:
        test表示只是统计可点个数,不真正设置enable
        ignoreEnable:为0表示对每个角色都重新设置Enable或取消Enable
            为1表示跳过已经设置为Enable的,但计入个数中
            为2表示跳过没有设置为Enable的,相当于只对标记了Enable的操作
    */



    //根据 所有武将 的 判定牌 等于/设置/取消 flag
    //type表示eFlags赋值方式(等于,设置,清除)
    //player = -1 表示所有,为0以上则除player外全部
    //返回设置为flags的武将数
    int flagAllPlayersByPanDing(QList<_Player*> list, BASE_PAI::_Flags flags, _Pai::_PaiValue pandingValue = _Pai::Value_All, bool test = false);

    int FlagAllPlayersByPaiCount(BASE_PAI::_Flags flags, int count = 0, int player = -1, bool test = false, int ignoreEnable = 0);

    //设置所有武将的装备(按areas设置)
    int FlagAllPlayersWeapon(BASE_PAI::_Flags eFlags, BASE_PAI::_Areas areas = BASE_PAI::Area_ZhuangBei, BASE_PAI::_FlagType type = BASE_PAI::FlagType_Set, int player = -1);

    //根据w的距离设置武将
    //type=1计算距离(包括马),type=2计算杀距离(包括武器和马)
    //返回可点个数,-1为错误
    int EnableAllPlayersByDistent(int player,int type, bool test = false, int ignoreEnable = 0);

    //根据装备设置武将
    //player为 -1 时全部武将,为具体值时不包括w; weapon=_Pai::Value_All 时全部,为具体时只是这个具体值;
    //返回可点个数,-1错误
    //int TestAllPlayersByWeapon(int w, int weaponValue, int ignoreEnable = 0);
    int EnableAllPlayersByZhuangBei(int player = -1, _Pai::_PaiValue value = _Pai::Value_All, bool test = false, int ignoreEnable = 0);
    int EnableAllPlayersByPanDing(int player = -1, _Pai::_PaiValue value = _Pai::Value_All, bool test = false, int ignoreEnable = 0);

    //int TestAllPlayersByShouPai(int w, int ignoreEnable = 0);
    int EnableAllPlayersByShouPai(int player = -1, bool test = false, int ignoreEnable = 0);






//电脑AI:
    //w为-1,则初始化一下
    _GameButtonValue ComputerChuPai(int player, int nStep, int canChoiceCount, _GameChuPaiType eType, int nValue);
    int ComputerQiPai(int player,int n);


//出牌函数:
/*
手牌: 0~19
装备: 20~23
判定: 24~29
敌人: 30~39(0~9)
按钮: 40~42(0~2)
*/
    virtual void WaitForChoice();

	//出牌阶段
	//nType:0:出牌阶段的出牌;1:被动出牌+nValue牌值;2:弃牌+nValue牌数
    //返回OK,CANCEL,GIVEUP
    virtual _GameButtonValue ChuPai(int w, _GameChuPaiType nType, int nValue, int nParam = -1);
    //根据nType,初始化第nStep个步骤,返回可点击牌数目
    int InitAllStatus(int w, _GameChuPaiType eType, int nValue, int nStep, int nParam);
    int RefreshAllFlags(int nStep);

    //eType分为主动被动,区别在于 弃牌 按钮 显隐
    int ChuPai_ZhangBa(int w, int nStep, _GameChuPaiType eType);
    int ChuPai_TanSu(int w, int nStep, _GameChuPaiType eType);




    void startChuPai(int w)
    {
        emit s_StartChuPai(w);
    }

    void stopChuPai(int w)
    {
        emit s_StopChuPai(w);
    }

    void ShowMessage(QString str)
    {
        emit s_ShowMessage(str);
    }

    void ShowChuPaiMessage(QString str)
    {
        emit s_ShowChuPaiMessage(str);
    }

    void ShowWenTiMessage(QString str)
    {
        //emit s_ShowWenTiMessage(str);
    }

    void Debug(QString str)
    {
        qDebug()<<str;
        emit s_ShowDebug(str);
    }

    void Sleep(int msec){msleep(msec);}

protected:
    void run();
};





class Game : public _GAME
{
    Q_OBJECT


//游戏初始化数据:
public:
    QList<_GameData*> dataList; //游戏数据(传输)

    QWaitCondition  m_waitForChoice;
    QWaitCondition  m_waitForQuestion;
    QWaitCondition  m_waitForNet;

    QMutex          m_mutexChoice;
    QMutex          m_mutexQuestion;
    QMutex          m_mutexNet;

    QMutex          m_mutexDataList;

    TcpSocket       socket;
    bool            netPlay;

public:
    Game(QObject *parent = NULL);
    virtual ~Game()
    {
        m_mutexChoice.tryLock();
        m_mutexChoice.unlock();
        m_mutexQuestion.tryLock();
        m_mutexQuestion.unlock();
        m_mutexNet.tryLock();
        m_mutexNet.unlock();

        qDeleteAll(dataList);
        dataList.clear();

    }

public:
    virtual int Init();
    //洗牌ok
    //将qipaidui随机放入paidui中,将所有qipaidui的leixing置为 -1,
    virtual void Xipai();
    virtual _GameButtonValue ChuPai(int w, _GameChuPaiType nType, int nValue, int nParam = -1);

    virtual bool WenTi(int w);
    virtual int ShowPlayersArea(int player)
    {
        emit s_ShowPlayersArea(player);
        return 0;
    }
    virtual int HidePlayersArea()
    {
        emit s_ShowPlayersArea(-1);
        return 0;
    }

    virtual int ShaiDian();


    virtual _GameStatus CheckGameOver()
    {
        int ret = _GAME::CheckGameOver();
        if(ret != Game_Status_Continue)
        {
            emit s_GameOver(ret);
            //exit();quit();
        }
        return eGameStatus;

    }


public:
    //等待UI解锁进程
    virtual void WaitForChoice()
    {
        //QMessageBox::information(NULL,"a","lock0");
        //QMessageBox::information(NULL,"a","lock1wait0");
        //m_mutex.lock();
        qDebug()<<"mutex0!!!";
        m_mutexChoice.tryLock();
        m_waitForChoice.wait(&m_mutexChoice);
        qDebug()<<"mutex1!!!";
        //m_mutex.unlock();
        //QMessageBox::information(NULL,"a","wait1unlock0");
        //QMessageBox::information(NULL,"a","unlock1");
        //QThread::currentThread()->wait()
    }

    void WaitForQuestion()
    {
        //QMessageBox::information(NULL,"a","lock0");
        //QMessageBox::information(NULL,"a","lock1wait0");
        //m_mutex.lock();
        qDebug()<<"mutex2!!!";
        m_mutexQuestion.tryLock();
        m_waitForQuestion.wait(&m_mutexQuestion);
        qDebug()<<"mutex3!!!";
        //m_mutexQuestion.unlock();
        //QMessageBox::information(NULL,"a","wait1unlock0");
        //QMessageBox::information(NULL,"a","unlock1");
        //QThread::currentThread()->wait()
    }

    void WaitForNet()
    {

        //注意:
        //unlock状态下:unlock函数会出错;QWaitCondition::wait函数会出错
        //所以保持lock状态
        m_mutexNet.tryLock();  //立即返回是否已锁定(肯定会锁定)
        m_waitForNet.wait(&m_mutexNet);
    }


    //等待网络响应(对方出牌)
    _GameData *WaitingForOthers();


    //锁定datalist并返回
    QList<_GameData*> *getDataList()
    {
        //Debug_Leamus(QString("m_mutexDataList.lock()"));
        m_mutexDataList.tryLock();
        return &dataList;
    }
    //释放datalist
    void releaseDataList()
    {
        //Debug_Leamus("m_mutexDataList.unlock()");
        m_mutexDataList.tryLock();
        m_mutexDataList.unlock();
    }
    void resetDataList()
    {
        QList<_GameData*> *list = getDataList();
        while(!list->isEmpty())
            delete list->takeFirst();
        releaseDataList();
    }


public slots:
    void pokeClicked(bool bClicked, QVariant v)
    {
        int n = v.toInt();
        if(!(m_PaiDui[n].flag() & BASE_PAI::Flag_Enable))
        {
            //qDebug()<<this->iType<<","<<this->iPositionPlayerID<<",ID(hide):"<<this->iID << "zvalue" << zValue();
            return;
        }

        //if(mouseButton == Qt::LeftButton && (this->iFlag & GAME_POKE_FLAG_ENABLE))
        {
            dianjipai.nPlayerID = m_PaiDui[n].positionPlayer();
            dianjipai.nType = m_PaiDui[n].positionArea();
            //if(dianjipai.nType == ITEM_TYPE_WUJIANG)
            //    dianjipai.nValue = m_PaiDui[n].positionPlayer();
            //else
                dianjipai.nValue = m_PaiDui[n].positionValue();
            dianjipai.iFlag = m_PaiDui[n].flag();
            dianjipai.pObject = m_PaiDui + n;
            m_PaiDui[n].setAFlag(BASE_PAI::Flag_Clicked);

            //qDebug()<<this->iType<<","<<this->iPositionPlayerID<<",ID:"<<this->iID << "zvalue:" << zValue();
            //if(event->button() == Qt::LeftButton)
            //    QMessageBox::information(NULL,"aa","aa");
            //emit s_ClickPai(dianjipai);
            m_waitForChoice.wakeAll();
        }
    }
    void playerClicked(bool bClicked, QVariant v)
    {
        //qDebug()<<v.toInt();
        //m_Player[v.toInt()].setFlag(BASE_PAI::Flag_Enable | BASE_PAI::Flag_Clicked);
        //return;

        int n = v.toInt();
        if(!(m_Player[n].flag() & BASE_PAI::Flag_Enable))
        {
            qDebug()<<"Player DisEnable却可以点击?";
            //m_Player[n].setAFlag(BASE_PAI::Flag_Clicked);
            //qDebug()<<this->iType<<","<<this->iPositionPlayerID<<",ID(hide):"<<this->iID << "zvalue" << zValue();
            return;
        }

        //if(mouseButton == Qt::LeftButton && (this->iFlag & GAME_POKE_FLAG_ENABLE))
        {
            dianjipai.nPlayerID = n;
            dianjipai.nType = BASE_PAI::Area_WuJiang;
            //if(dianjipai.nType == ITEM_TYPE_WUJIANG)
                dianjipai.nValue = n;
            //else
                //dianjipai.nValue = m_PaiDui[n].positionValue();
                dianjipai.iFlag = m_Player[n].flag();
                dianjipai.pObject = m_Player + n;
                //qDebug()<<"flag:"<<m_Player[n].flag();
                m_Player[n].setAFlag(BASE_PAI::Flag_Clicked);

            //qDebug()<<this->iType<<","<<this->iPositionPlayerID<<",ID:"<<this->iID << "zvalue:" << zValue();
            //if(event->button() == Qt::LeftButton)
            //    QMessageBox::information(NULL,"aa","aa");
            //emit s_ClickPai(dianjipai);
            m_waitForChoice.wakeAll();
        }
    }

    //-1:时间超时,0~2:按钮;10以上:调试
    void buttonClicked(int button);

    void debugButton(int button, QVariant v);

    void questionAnswerd(int userAnswer)
    {
        m_waitForQuestion.wakeAll();
    }

};

#endif //GAME_H
